package common

import (
	"errors"
	"fmt"
	"github.com/golang-jwt/jwt/v5"
	"time"
)

// type RegisteredClaims struct {
// 签发人
// Issuer string `json:"iss,omitempty"`
// 主题
// Subject string `json:"sub,omitempty"`
// 受众
// Audience ClaimStrings `json:"aud,omitempty"`
// 过期时间
// ExpiresAt *NumericDate `json:"exp,omitempty"`
// 生效时间
// NotBefore *NumericDate `json:"nbf,omitempty"`
// 签发时间
// IssuedAt *NumericDate `json:"iat,omitempty"`
// 编号
// ID string `json:"jti,omitempty"`
//	}

// CustomClaims 自定义声明类型 并内嵌jwt.RegisteredClaims
// jwt包自带的jwt.RegisteredClaims只包含了官方字段
// 假设我们这里需要额外记录一个username字段，所以要自定义结构体
// 如果想要保存更多信息，都可以添加到这个结构体中
type CustomClaims struct {
	// 可根据需要自行添加字段
	Name                 string `json:"username"`
	jwt.RegisteredClaims        // 内嵌标准的声明
}

//这是一个生成 JWT (JSON Web Token) 的函数。它接受一个名称作为参数，并创建了一个声明的数据结构（CustomClaims）。
//在声明中，我们包含了自定义字段 Name，以及标准的注册声明（RegisteredClaims），包括过期时间（ExpiresAt）和签发人（Issuer）。
//然后，使用 JWT 库创建一个 JWT 对象，并指定签名算法为 HS256。最后，调用 SignedString 方法，传入密钥（SecretKey），生成签名字符串，并返回给调用者。
//请注意，其中的 SecretKey 是一个密钥，用于对签名进行加密和验证，应该是一个安全的随机字符串。

// GenToken 生成JWT
func GenToken(Name string) (string, error) {
	// 创建一个声明的数据
	claims := CustomClaims{
		Name, // 自定义字段
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 12)), // 定义过期时间
			Issuer:    "user",                                             // 签发人
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 生成签名字符串
	return token.SignedString([]byte(SecretKey))
}

//这是一个解析 JWT（JSON Web Token）的函数。它接受一个 token 字符串作为参数，并返回一个 CustomClaims 对象（声明的数据结构）和一个错误对象。
//在函数内部，首先创建了一个 CustomClaims 对象，并进行了类型断言，以便能够正确地解析 token 中的声明数据。
//然后，调用 jwt.ParseWithClaims 方法，以给定的 token 字符串和 CustomClaims 对象进行解析，同时验证签名。
//解析时，会通过传入的回调函数获取用于验证令牌签名的密钥 SecretKey。如果密钥不匹配或解析过程中出现任何错误，将返回相应的错误。
//最后，通过检查 token.Valid 来判断令牌是否有效，如果有效则返回解析后的 CustomClaims 对象，如果无效则返回错误信息：invalid token（无效的令牌）。
//请注意，解析令牌和验证令牌签名是重要的安全步骤，并且应该使用正确的密钥和算法进行操作，以确保令牌的真实性和完整性。

func ParseToken(tokenString string) (*CustomClaims, error) {
	// 解析token
	//新建一个对象
	var mc = new(CustomClaims)

	token, err := jwt.ParseWithClaims(tokenString, mc, func(token *jwt.Token) (i interface{}, err error) {
		// 根据令牌中的算法类型获取相应的秘钥
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		// 返回用于验证令牌签名的秘钥
		return []byte(SecretKey), nil
	})
	//报错，返回空
	if err != nil {
		return nil, err
	}
	// 对token对象中的Claim进行类型断言
	//如果token没有过期，则返回mc对象
	//否则返回空
	//没过期返回
	if token.Valid { // 校验token
		return mc, nil
	}
	//返回错误信息：invalid token（无效的token）
	return nil, errors.New("invalid token")
}
